home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / Astro / astrolog / Source / xdriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  40.4 KB  |  1,383 lines

  1. /*
  2. ** Astrolog (Version 4.10) File: xdriver.c
  3. **
  4. ** IMPORTANT NOTICE: the graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1994 by Walter D. Pullen
  6. ** (cruiser1@stein.u.washington.edu). Permission is granted to freely
  7. ** use and distribute these routines provided one doesn't sell,
  8. ** restrict, or profit from them in any way. Modification is allowed
  9. ** provided these notices remain with any altered or edited versions of
  10. ** the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 3/19/1994.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40. #ifdef GRAPH
  41.  
  42. #ifdef X11
  43. /* Size of the Astrolog X11 icon. These values are defined in xdata.c too. */
  44.  
  45. #define icon_width 63
  46. #define icon_height 32
  47. #endif
  48.  
  49. #ifdef MSG
  50. /* PC specific global variables. */
  51.  
  52. int hiresmode = DEFHIRESMODE;    /* 'High-resolution' graphics mode. */
  53. int loresmode = DEFLORESMODE;    /* 'Flicker-free' graphics mode.    */
  54. int xscreen   = -1000;           /* Current graphics mode.           */
  55. struct videoconfig config;       /* State of current graphics mode.  */
  56. #endif
  57.  
  58.  
  59. /*
  60. ******************************************************************************
  61. ** Interactive Screen Graphics Routines.
  62. ******************************************************************************
  63. */
  64.  
  65. #ifdef X11
  66. /* Allocate a color from the present colormap. Given a string like "red" or */
  67. /* "blue" allocate this color and return a value specifying it.             */
  68.  
  69. colrgb XMakeColor(name)
  70. char *name;
  71. {
  72.   XColor col;
  73.   XParseColor(disp, cmap, name, &col);
  74.   XAllocColor(disp, cmap, &col);
  75.   return col.pixel;
  76. }
  77. #endif
  78.  
  79.  
  80. /* Set up all the colors used by the program, i.e. the foreground and   */
  81. /* background colors, and all the colors in the object arrays, based on */
  82. /* whether or not we are in monochrome and/or reverse video mode.       */
  83.  
  84. void XColorInit()
  85. {
  86.   int i;
  87.  
  88. #ifdef X11
  89.   if (!xfile) {
  90.     cmap = XDefaultColormap(disp, screen);
  91.     for (i = 0; i < 16; i++)
  92.       rgbind[i] = XMakeColor(rgbname[i]);
  93.   }
  94. #endif
  95.   on  = mainansi[!xreverse];
  96.   off = mainansi[xreverse];
  97.   hilite = xcolor ? mainansi[2+xreverse] : on;
  98.   gray   = xcolor ? mainansi[3-xreverse] : on;
  99.   for (i = 0; i <= 6; i++)
  100.     maincolor[i]    = xcolor ? mainansi[i]    : on;
  101.   for (i = 0; i <= 7; i++)
  102.     rainbowcolor[i] = xcolor ? rainbowansi[i] : on;
  103.   for (i = 0; i < 4; i++)
  104.     elemcolor[i]    = xcolor ? elemansi[i]    : on;
  105.   for (i = 0; i <= ASPECTS; i++)
  106.     aspectcolor[i]  = xcolor ? aspectansi[i]  : on;
  107.   for (i = 0; i <= total; i++)
  108.     objectcolor[i]  = xcolor ? objectansi[i]  : on;
  109. #ifdef X11
  110.   if (!xfile) {
  111.     XSetBackground(disp, gc,   rgbind[off]);  /* Initialize X window colors. */
  112.     XSetForeground(disp, pmgc, rgbind[off]);
  113.   }
  114. #endif
  115. }
  116.  
  117.  
  118. #ifdef ISG
  119. /* This routine opens up and initializes a window and prepares it to be */
  120. /* drawn upon, and gets various information about the display, too.     */
  121.  
  122. void XBegin()
  123. {
  124. #ifdef X11
  125.   disp = XOpenDisplay(dispname);
  126.   if (!disp) {
  127.     PrintError("Can't open display.");
  128.     Terminate(_FATAL);
  129.   }
  130.   screen = DefaultScreen(disp);
  131.   bg = BlackPixel(disp, screen);
  132.   fg = WhitePixel(disp, screen);
  133.   hint.x = offsetx; hint.y = offsety;
  134.   hint.width = chartx; hint.height = charty;
  135.   hint.min_width = BITMAPX1; hint.min_height = BITMAPY1;
  136.   hint.max_width = BITMAPX;  hint.max_height = BITMAPY;
  137.   hint.flags = PPosition | PSize | PMaxSize | PMinSize;
  138. #if FALSE
  139.   wmhint = XGetWMHints(disp, window);
  140.   wmhint->input = True;
  141.   XSetWMHints(disp, window, wmhint);
  142. #endif
  143.   depth = DefaultDepth(disp, screen);
  144.   if (depth < 5) {
  145.     xmono = TRUE;      /* Is this a monochrome monitor? */
  146.     xcolor = FALSE;
  147.   }
  148.   root = RootWindow(disp, screen);
  149.   if (xroot)
  150.     window = root;     /* If -XB in effect, we'll use the root window. */
  151.   else
  152.     window = XCreateSimpleWindow(disp, DefaultRootWindow(disp),
  153.       hint.x, hint.y, hint.width, hint.height, 5, fg, bg);
  154.   pixmap = XCreatePixmap(disp, window, chartx, charty, depth);
  155.   icon = XCreateBitmapFromData(disp, DefaultRootWindow(disp),
  156.     icon_bits, icon_width, icon_height);
  157.   if (!xroot)
  158.     XSetStandardProperties(disp, window, appname, appname, icon,
  159.       (char PTR PTR)xkey, 0, &hint);
  160.  
  161.   /* We have two graphics workareas. One is what the user currently sees in */
  162.   /* the window, and the other is what we are currently drawing on. When    */
  163.   /* done, we can quickly copy this to the viewport for a smooth look.      */
  164.  
  165.   gc = XCreateGC(disp, window, 0, 0);
  166.   XSetGraphicsExposures(disp, gc, 0);
  167.   pmgc = XCreateGC(disp, window, 0, 0);
  168.   XColorInit();                            /* Go set up colors. */
  169.   if (!xroot)
  170.     XSelectInput(disp, window, KeyPressMask | StructureNotifyMask |
  171.       ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
  172.   XMapRaised(disp, window);
  173.   XSync(disp, 0);
  174.   XFillRectangle(disp, pixmap, pmgc, 0, 0, chartx, charty);
  175.  
  176. #else /* MSG */
  177.  
  178.   if (!IsValidResmode(xscreen))    /* Initialize graphics mode to hi-res. */
  179.     xscreen = hiresmode;
  180.   _setvideomode(xscreen);
  181.   if (_grstatus()) {
  182.     PrintError("Can't enter graphics mode.");
  183.     Terminate(_FATAL);
  184.   }
  185.   _getvideoconfig((struct videoconfig far *) &config);
  186.   if (config.numcolors < 16) {
  187.     xmono = TRUE;
  188.     xcolor = FALSE;
  189.   }
  190.   _remapallpalette((long FAR *) rgb);
  191.   _setactivepage(0);
  192.   _setvisualpage(0);
  193.   XColorInit();
  194. #ifdef MOUSE
  195.   if (MouseInit() > 0)
  196.     SetPtrVis(SHOW);
  197. #endif
  198.   textrows = abs(textrows);    /* Make sure we reset textrows upon restart. */
  199. #endif /* MSG */
  200. }
  201.  
  202.  
  203. /* Add a certain amount of time to the current hour/day/month/year quantity */
  204. /* defining the present chart. This is used by the chart animation feature. */
  205. /* We can add or subtract anywhere from 1 to 9 seconds, minutes, hours,     */
  206. /* days, months, years, decades, centuries, or millenia in any one call.    */
  207. /* This is mainly just addition to the appropriate quantity, but we have    */
  208. /* to check for overflows, e.g. Dec 30 + 3 days = Jan 2 of Current year + 1 */
  209.  
  210. void AddTime(mode, toadd)
  211. int mode, toadd;
  212. {
  213.   int d;
  214.   real h, m;
  215.  
  216.   h = floor(TT);
  217.   m = FRACT(TT)*100.0;
  218.   if (mode == 1)
  219.     m += 1.0/60.0*(real)toadd;    /* Add seconds. */
  220.   else if (mode == 2)
  221.     m += (real)toadd;             /* add minutes. */
  222.  
  223.   /* Add hours, either naturally or if minute value overflowed. */
  224.  
  225.   if (m < 0.0 || m >= 60.0 || mode == 3) {
  226.     if (m >= 60.0) {
  227.       m -= 60.0; toadd = SGN(toadd);
  228.     } else if (m < 0.0) {
  229.       m += 60.0; toadd = SGN(toadd);
  230.     }
  231.     h += (real)toadd;
  232.   }
  233.  
  234.   /* Add days, either naturally or if hour value overflowed. */
  235.  
  236.   if (h >= 24.0 || h < 0.0 || mode == 4) {
  237.     if (h >= 24.0) {
  238.       h -= 24.0; toadd = SGN(toadd);
  239.     } else if (h < 0.0) {
  240.       h += 24.0; toadd = SGN(toadd);
  241.     }
  242.     DD = AddDay(MM, DD, YY, toadd);
  243.   }
  244.  
  245.   /* Add months, either naturally or if day value overflowed. */
  246.  
  247.   if (DD > (d = DayInMonth(MM, YY)) || DD < 1 || mode == 5) {
  248.     if (DD > d) {
  249.       DD -= d; toadd = SGN(toadd);
  250.     } else if (DD < 1) {
  251.       DD += DayInMonth(Mod12(MM - 1), YY);
  252.       toadd = SGN(toadd);
  253.     }
  254.     MM += toadd;
  255.   }
  256.  
  257.   /* Add years, either naturally or if month value overflowed. */
  258.  
  259.   if (MM > 12 || MM < 1 || mode == 6) {
  260.     if (MM > 12) {
  261.       MM -= 12; toadd = SGN(toadd);
  262.     } else if (MM < 1) {
  263.       MM += 12; toadd = SGN(toadd);
  264.     }
  265.     YY += toadd;
  266.   }
  267.   if (mode == 7)
  268.     YY += 10 * toadd;      /* Add decades.   */
  269.   else if (mode == 8)
  270.     YY += 100 * toadd;     /* Add centuries. */
  271.   else if (mode == 9)
  272.     YY += 1000 * toadd;    /* Add millenia.  */
  273.   TT = h+m/100.0;          /* Recalibrate hour time. */
  274. }
  275.  
  276.  
  277. /* Animate the current chart based on the given values indicating how much  */
  278. /* to update by. We update and recast the current chart info appropriately. */
  279.  
  280. void Animate(mode, toadd)
  281. int mode, toadd;
  282. {
  283.   if (modex == MODEW || modex == MODEG || modex == MODEP) {
  284.     degree += toadd;
  285.     if (degree >= DEGD)     /* For animating globe display, add */
  286.       degree -= DEGD;       /* in appropriate degree value.     */
  287.     else if (degree < 0)
  288.       degree += DEGD;
  289.   } else {
  290.     if (mode == 10) {
  291. #ifdef TIME
  292.       /* For the continuous chart update to present moment */
  293.       /* animation mode, go get whatever time it is now.   */
  294.       InputData("now");
  295. #else
  296.       SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  297.       AddTime(1, toadd);
  298. #endif
  299.     } else {  /* Otherwise add on appropriate time vector to chart info. */
  300.       SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  301.       AddTime(mode, toadd);
  302.     }
  303.     SetMain(MM, DD, YY, TT, ZZ, OO, AA);
  304.     if (relation)
  305.       CastRelation(FALSE);
  306.     else
  307.       CastChart(TRUE);
  308.   }
  309. }
  310.  
  311.  
  312. /* Print a list of every key that one can press in an X window to do a */
  313. /* certain function, and a description of what it does. This list gets */
  314. /* displayed whenever one presses the 'H' or '?' key in the window.    */
  315.  
  316. void XDisplayKeys()
  317. {
  318.   char string[STRING];
  319.  
  320.   sprintf(string, "\n%s window keypress options (version %s):", appname,
  321.     VERSION);
  322.   Prints(string);
  323.   Prints(" Press 'H' or '?' to display this list of key options.");
  324.   Prints(" Press 'p' to toggle pause status on or off.");
  325.   Prints(" Press 'x' to toggle fg/bg colors on screen.");
  326.   Prints(" Press 'm' to toggle color/monochrome display on screen.");
  327.   Prints(" Press 'i' to toggle status of the minor chart modification.");
  328.   Prints(" Press 'T' to toggle header info on current chart on screen.");
  329.   Prints(" Press 'b' to toggle drawing of a border around the chart.");
  330.   Prints(" Press 'l' to toggle labeling of object points in chart.");
  331.   Prints(" Press 'v' to display current chart positions on text screen.");
  332.   Prints(" Press 'R', 'C', 'u', 'U' to toggle restriction status of minor");
  333.   Prints("       objects, minor house cusps, uranian planets, and stars.");
  334.   Prints(" Press 'c' to toggle relationship comparison chart mode.");
  335.   Prints(" Press 's', 'h', 'f', 'F' to toggle status of sidereal zodiac,");
  336.   Prints("       heliocentric charts, domal charts, and decan charts.");
  337.   Prints(" Press 'O' and 'o' to recall/store a previous chart from memory.");
  338. #ifdef X11
  339.   Prints(" Press 'B' to dump current window contents to root background.");
  340. #else
  341.   Prints(" Press 'B' to resize chart display to full size of screen.");
  342. #endif
  343.   Prints(" Press 'Q' to resize chart display to a square.");
  344.   Prints(" Press '<' and '>' to decrease/increase the scale size of the");
  345.   Prints("       glyphs and the size of world map.");
  346.   Prints(" Press '[' and ']' to decrease/increase tilt in globe display.");
  347.   Prints(" Press '+' and '-' to add/subtract a day from current chart.");
  348. #ifdef TIME
  349.   Prints(" Press 'n' to set chart information to current time now.");
  350. #endif
  351.   Prints(" Press 'N' to toggle animation status on or off. Charts will");
  352.   Prints("       be updated to current status and globe will rotate.");
  353.   Prints(" Press '!'-'(' to begin updating current chart by adding times.");
  354.   Prints("       !: seconds, @: minutes, #: hours, $: days, %: months,");
  355.   Prints("       ^: years, &: years*10, *: years*100, (: years*1000.");
  356.   Prints(" Press 'r' to reverse direction of time-lapse or animation.");
  357.   Prints(" Press '1'-'9' to set rate of animation to 'n' degrees, etc.");
  358. #ifdef MSG
  359.   Prints(" Press '1'-'9' to determine section of chart to show if clipped.");
  360. #endif
  361.   Prints(
  362.     " Press 'V','L','A','Z','S','E','W','G','P' to switch to normal (_v),");
  363.   Prints(
  364.     "       astro-graph (_L), grid (_g), local (_Z), space (_S), ephemeris");
  365.   Prints("       (_E), world map (_XW), globe (_XG), and polar (_XP) modes.");
  366.   Prints(" Press '0' to toggle between _Z,_Z0 & _XW,_XW0 & _E,_Ey modes.");
  367.   Prints(" Press 'space' to force redraw of current graphics display.");
  368. #ifdef MSG
  369.   Prints(" Press 'tab' to toggle between graphics resolutions.");
  370. #endif
  371.   Prints(" Press 'q' to terminate the window and program.");
  372. #ifdef MOUSE
  373.   printl();
  374. #ifdef X11
  375.   Prints(" Left   mouse button: Draw line strokes on chart in window.");
  376.   Prints(" Middle mouse button: Print coordinates of pointer on world map.");
  377.   Prints(" Right  mouse button: Terminate the window and program.");
  378. #endif
  379. #ifdef MSG
  380.   Prints(" Left  mouse button: Draw line strokes on chart in screen.");
  381.   Prints(" Right mouse button: Set coordinates to pointer on world map.");
  382. #endif
  383. #endif /* MOUSE */
  384. }
  385.  
  386.  
  387. /* Given two chart size values, adjust them such that the chart will look */
  388. /* "square". We round the higher value down and check certain conditions. */
  389.  
  390. void XSquare(x, y, force)
  391. int *x, *y, force;
  392. {
  393.   if (!force && !ISSQUARE)    /* Unless we want to force a square, realize */
  394.     return;                   /* that some chart look better rectangular.  */
  395.   if (*x > *y)
  396.     *x = *y;
  397.   else
  398.     *y = *x;
  399. #ifdef MSG
  400.   if (ISEGA(xscreen))         /* Scale horizontal size if we're in a PC */
  401.     *x = EGATOVGA(*x);        /* graphics mode without "square" pixels. */
  402.     else if (ISCGA(xscreen))
  403.     *x = CGATOVGA(*x);
  404. #endif
  405.   if (ISSIDEBAR)    /* Take into account chart's sidebar, if any. */
  406.     *x += SIDET;
  407. }
  408.  
  409.  
  410. /* This routine gets called after an X window is brought up and displayed   */
  411. /* on the screen. It loops, processing key presses, mouse clicks, etc, that */
  412. /* the window receives, until the user specifies they want to exit program. */
  413.  
  414. void XSpin()
  415. {
  416. #ifdef X11
  417.   XEvent event;
  418.   int xresize = FALSE, xredraw = TRUE;
  419. #else
  420. #ifdef MOUSE
  421.   EVENT event;
  422. #endif
  423.   int xresize = TRUE, xredraw = FALSE;
  424. #endif
  425.   int xbreak = FALSE, xpause = FALSE, xcast = FALSE, xcorner = 7,
  426.     mousex = -1, mousey = -1, buttonx = -1, buttony = -1, dir = 1, length, i;
  427.   colpal coldrw = hilite;
  428.  
  429.   xnow = -xnow;
  430.   while (!xbreak) {
  431.  
  432.     /* Some chart windows, like the world maps and aspect grids, should */
  433.     /* always be a certian size, so correct if a resize was attempted.  */
  434.  
  435.     if (modex == MODEL || modex == MODEW) {
  436.       length = DEGD*SCALE+2;
  437.       if (chartx != length) {
  438.         chartx = length;
  439.         xresize = TRUE;
  440.       }
  441.       length = (90*2+1)*SCALE+2;
  442.       if (charty != length) {
  443.         charty = length;
  444.         xresize = TRUE;
  445.       }
  446.     } else if (modex == MODEg) {
  447.       if (chartx !=
  448.         (length = (gridobjects + (relation <= DASHr0))*CELLSIZE*SCALE+1)) {
  449.         chartx = length;
  450.         xresize = TRUE;
  451.       } if (charty != length) {
  452.         charty = length;
  453.         xresize = TRUE;
  454.       }
  455.  
  456.     /* Make sure the window isn't too large or too small. */
  457.  
  458.     } else {
  459.         if (chartx < BITMAPX1) {
  460.           chartx = BITMAPX1;
  461.           xresize = TRUE;
  462.         } else if (chartx > BITMAPX) {
  463.           chartx = BITMAPX;
  464.           xresize = TRUE;
  465.         }
  466.         if (charty < BITMAPY1) {
  467.           charty = BITMAPY1;
  468.           xresize = TRUE;
  469.         } else if (charty > BITMAPY) {
  470.           charty = BITMAPY;
  471.           xresize = TRUE;
  472.         }
  473.         }
  474.  
  475.     /* If in animation mode, ensure we are in the flicker free resolution. */
  476.  
  477.     if (xnow < 0) {
  478.       xnow = -xnow;
  479. #ifdef MSG
  480.       if (xscreen == hiresmode) {
  481.         xscreen = loresmode;
  482.         XBegin();
  483.         chartx = config.numxpixels;
  484.         charty = config.numypixels;
  485.         XSquare(&chartx, &charty, FALSE);
  486.         xresize = TRUE;
  487.       }
  488. #endif
  489.     }
  490.  
  491.     /* Physically resize window if we've changed the size parameters. */
  492.  
  493.     if (xresize) {
  494.       xresize = FALSE;
  495. #ifdef X11
  496.       XResizeWindow(disp, window, chartx, charty);
  497.       XFreePixmap(disp, pixmap);
  498.       pixmap = XCreatePixmap(disp, window, chartx, charty, depth);
  499. #else
  500.       if (config.numxpixels > chartx)
  501.         offsetx = (config.numxpixels - chartx) >> 1;
  502.       else {
  503.         if (xcorner % 3 == 1)
  504.           offsetx = 0;
  505.         else if (xcorner % 3 == 0)
  506.           offsetx = -chartx + config.numxpixels;
  507.         else
  508.           offsetx = -(chartx - config.numxpixels) / 2;
  509.       }
  510.       if (config.numypixels > charty)
  511.         offsety = (config.numypixels - charty) >> 1;
  512.       else {
  513.         if (xcorner > 6)
  514.           offsety = 0;
  515.         else if (xcorner < 4)
  516.           offsety = -charty + config.numypixels;
  517.         else
  518.           offsety = -(charty - config.numypixels) / 2;
  519.       }
  520. #endif
  521.       xredraw = TRUE;
  522.     }
  523.  
  524.     /* Recast chart if the chart information has changed any. */
  525.  
  526.     if (xcast) {
  527.       xcast = FALSE;
  528.       SetCore(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  529.       if (relation)
  530.         CastRelation(FALSE);
  531.       else
  532.         CastChart(TRUE);
  533.       xredraw = TRUE;
  534.     }
  535.     if (xnow && !xpause)
  536.       xredraw = TRUE;
  537.  
  538.     /* Update the screen if anything has changed since last time around. */
  539.  
  540.     if (xredraw) {
  541.       xredraw = FALSE;
  542.  
  543.       /* If we're in animation mode, change the chart info appropriately. */
  544.  
  545.       if (xnow)
  546.         Animate(xnow, dir);
  547. #ifdef X11
  548.       XFillRectangle(disp, pixmap, pmgc, 0, 0, chartx, charty);
  549. #else /* MSG */
  550. #ifdef MOUSE
  551.       SetPtrVis(HIDE);
  552. #endif
  553.       if (config.numvideopages > 1)
  554.         _setactivepage(_getactivepage() == 0);
  555. #endif /* MSG */
  556.       XChart();
  557. #ifdef X11
  558.       XSync(disp, 0);
  559.       XCopyArea(disp, pixmap, window, gc, 0, 0, chartx, charty, 0, 0);
  560. #else /* MSG */
  561.       if (config.numvideopages > 1)
  562.         _setvisualpage(_getactivepage());
  563. #ifdef MOUSE
  564.       if (!xnow)
  565.         SetPtrVis(SHOW);
  566. #endif
  567. #endif /* MSG */
  568.     }  /* if */
  569.  
  570.     /* Now process what's on the event queue, i.e. any keys pressed, etc. */
  571.  
  572. #ifdef X11
  573.     if (XEventsQueued(disp, QueuedAfterFlush /*QueuedAfterReading*/ )) {
  574.       XNextEvent(disp, &event);
  575.  
  576.       /* Restore what's on window if a part of it gets uncovered. */
  577.  
  578.       if (event.type == Expose && event.xexpose.count == 0) {
  579.         XSync(disp, 0);
  580.         XCopyArea(disp, pixmap, window, gc, 0, 0, chartx, charty, 0, 0);
  581.       }
  582.       switch (event.type) {
  583.  
  584.       /* Check for a manual resize of window by user. */
  585.  
  586.       case ConfigureNotify:
  587.         chartx = event.xconfigure.width;
  588.         charty = event.xconfigure.height;
  589.         XFreePixmap(disp, pixmap);
  590.         pixmap = XCreatePixmap(disp, window, chartx, charty, depth);
  591.         xredraw = TRUE;
  592.         break;
  593.       case MappingNotify:
  594.         XRefreshKeyboardMapping((XMappingEvent PTR)&event);
  595.         break;
  596.  
  597. #ifdef MOUSE
  598.       /* Process any mouse buttons the user pressed. */
  599.  
  600.       case ButtonPress:
  601.         mousex = event.xbutton.x; mousey = event.xbutton.y;
  602.         if (event.xbutton.button == Button1) {
  603.           DrawColor(hilite);
  604.           DrawPoint(mousex, mousey);
  605.           XSync(disp, 0);
  606.           XCopyArea(disp, pixmap, window, gc, 0, 0, chartx, charty, 0, 0);
  607.         } else if (event.xbutton.button == Button2 &&
  608.           (modex == MODEL || modex == MODEW) && degree == 0) {
  609.           Lon = DEGHALF-(real)(event.xbutton.x-1)/(real)(chartx-2)*DEGREES;
  610.           Lat =  DEGQUAD-(real)(event.xbutton.y-1)/(real)(charty-2)*181.0;
  611.           fprintf(S, "Mouse is at %s.\n", CharLocation(Lon, Lat, 60.0));
  612.         } else if (event.xbutton.button == Button3)
  613.           xbreak = TRUE;
  614.         break;
  615.  
  616.       /* Check for user dragging any of the mouse buttons across window. */
  617.  
  618.       case MotionNotify:
  619.         DrawColor(coldrw);
  620.         DrawLine(mousex, mousey, event.xbutton.x, event.xbutton.y);
  621.         XSync(disp, 0);
  622.         XCopyArea(disp, pixmap, window, gc, 0, 0, chartx, charty, 0, 0);
  623.         mousex = event.xbutton.x; mousey = event.xbutton.y;
  624.         break;
  625. #endif
  626.  
  627.       /* Process any keys user pressed in window. */
  628.  
  629.       case KeyPress:
  630.         length = XLookupString((XKeyEvent PTR)&event, xkey, 10, &key, 0);
  631.         if (length == 1) {
  632.           i = xkey[0];
  633. #else /* MSG */
  634. #ifdef MOUSE
  635.       if (!xnow && GetMouseEvent((EVENT *)&event)) {
  636.  
  637.         /* If the left button is down, draw on the screen. */
  638.         if (event.fsBtn == LEFT_DOWN && mousex >= 0) {
  639.           SetPtrVis(HIDE);
  640.           DrawColor(coldrw);
  641.           _moveto(mousex, mousey);
  642.           buttonx = event.x; buttony = event.y;
  643.           _lineto(buttonx, buttony);
  644.  
  645.         /* If the right button is down, change the default location. */
  646.         } else if (event.fsBtn == RIGHT_DOWN) {
  647.           if ((modex == MODEL || modex == MODEW) && degree == 0) {
  648.             Lon = DEGHALF-(real)(event.x-offsetx)/(real)(chartx-2)*DEGREES;
  649.             if (Lon < -DEGHALF)
  650.               Lon = -DEGHALF;
  651.             else if (Lon > DEGHALF)
  652.               Lon = DEGHALF;
  653.             Lat =  DEGQUAD-(real)(event.y-offsety)/(real)(charty-2)*181.0;
  654.             if (Lat < -DEGQUAD)
  655.               Lat = -DEGQUAD;
  656.             else if (Lat > DEGQUAD)
  657.               Lat = DEGQUAD;
  658.             xcast = TRUE;
  659.           /* Right button means draw lines if not in a world map mode. */
  660.           } else if (buttonx >= 0) {
  661.             SetPtrVis(HIDE);
  662.             DrawColor(coldrw);
  663.             _moveto(buttonx, buttony);
  664.             _lineto(event.x, event.y);
  665.           }
  666.  
  667.         /* Middle button (which most PC's don't have) mean exit program. */
  668.         } else if (event.fsBtn == MIDDLE_DOWN)
  669.           xbreak = TRUE;
  670.  
  671.         mousex = event.x; mousey = event.y;
  672.         SetPtrVis(SHOW);
  673.       } else
  674. #endif
  675.         if (kbhit()) {
  676.           i = getch();
  677. #endif /* MSG */
  678.           switch (i) {
  679.           case ' ':
  680.             xredraw = TRUE;
  681.             break;
  682.           case 'p':
  683.             xpause = !xpause;
  684.             break;
  685.           case 'r':
  686.             dir = -dir;
  687.             break;
  688.           case 'x':
  689.             xreverse = !xreverse;
  690.             XColorInit();
  691.             xredraw = TRUE;
  692.             break;
  693.           case 'm':
  694.             if (!xmono) {
  695.               xcolor = !xcolor;
  696. #ifdef MSG
  697.               _getvideoconfig((struct videoconfig far *) &config);
  698. #endif
  699.               XColorInit();
  700.               xredraw = TRUE;
  701.             }
  702.             break;
  703.           case 'B':
  704. #ifdef X11
  705.             XSetWindowBackgroundPixmap(disp, root, pixmap);
  706.             XClearWindow(disp, root);
  707. #else
  708.             chartx = config.numxpixels;
  709.             charty = config.numypixels;
  710.             XSquare(&chartx, &charty, FALSE);
  711.             xresize = TRUE;
  712. #endif
  713.             break;
  714.           case 'T':
  715.             xtext = !xtext;
  716.             xredraw = TRUE;
  717.             break;
  718.           case 'i':
  719.             xbonus = !xbonus;
  720.             xredraw = TRUE;
  721.             break;
  722.           case 'b':
  723.             xborder = !xborder;
  724.             xredraw = TRUE;
  725.             break;
  726.           case 'l':
  727.             xlabel = !xlabel;
  728.             xredraw = TRUE;
  729.             break;
  730.           case '<':
  731.             if (scale > 100) {
  732.               scale -= 100;
  733.               xresize = TRUE;
  734.             }
  735.             break;
  736.           case '>':
  737.             if (scale < 400) {
  738.               scale += 100;
  739.               xresize = TRUE;
  740.             }
  741.             break;
  742.           case '[':
  743.             if (modex == MODEG) {
  744.               tilt = tilt > -DEGQUAD ? tilt-11.25 : -DEGQUAD;
  745.               xredraw = TRUE;
  746.             }
  747.             break;
  748.           case ']':
  749.             if (modex == MODEG) {
  750.               tilt = tilt < DEGQUAD ? tilt+11.25 : DEGQUAD;
  751.               xredraw = TRUE;
  752.             }
  753.             break;
  754.           case 'Q':
  755.             XSquare(&chartx, &charty, TRUE);
  756.             xresize = TRUE;
  757.             break;
  758.           case 'R':
  759.             for (i = _CHI; i < THINGS; i++)
  760.               ignore[i] = !ignore[i];
  761.             ignore[_FOR] = !ignore[_FOR]; ignore[_VTX] = !ignore[_VTX];
  762.             xredraw = TRUE;
  763.             break;
  764.           case 'C':
  765.             operation ^= DASHC;
  766.             for (i = C_LO; i <= C_HI; i++)
  767.               ignore[i] = !(operation & DASHC) || !ignore[i];
  768.             xcast = TRUE;
  769.             break;
  770.           case 'u':
  771.             operation ^= DASHu;
  772.             for (i = U_LO; i <= U_HI; i++)
  773.               ignore[i] = !(operation & DASHu) || !ignore[i];
  774.             xcast = TRUE;
  775.             break;
  776.           case 'U':
  777.             universe = !universe;
  778.             for (i = S_LO; i <= S_HI; i++)
  779.               ignore[i] = !universe || !ignore[i];
  780.             xcast = TRUE;
  781.             break;
  782.           case 'c':
  783.             if (!relation) {
  784.               relation = DASHr0;
  785.               SetTwin(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  786.             } else
  787.               relation = 0;
  788.             xcast = TRUE;
  789.             break;
  790.           case 's':
  791.             operation ^= DASHs;
  792.             xcast = TRUE;
  793.             break;
  794.           case 'h':
  795.             centerplanet = centerplanet ? 0 : 1;
  796.             xcast = TRUE;
  797.             break;
  798.           case 'f':
  799.             operation ^= DASHf;
  800.             xcast = TRUE;
  801.             break;
  802.           case 'F':
  803.             operation ^= DASH3;
  804.             xcast = TRUE;
  805.             break;
  806.           case '+':
  807.             Animate(4, abs(dir));
  808.             xcast = TRUE;
  809.             break;
  810.           case '-':
  811.             Animate(4, -abs(dir));
  812.             xcast = TRUE;
  813.             break;
  814.           case 'o':
  815.             SetSave(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  816.             break;
  817.           case 'O':
  818.             SetMain(MonX, DayX, YeaX, TimX, ZonX, LonX, LatX);
  819.             xcast = TRUE;
  820.             break;
  821. #ifdef TIME
  822.           case 'n':
  823.             InputData("now");
  824.             SetMain(MM, DD, YY, TT, ZZ, OO, AA);
  825.             xcast = TRUE;
  826.             break;
  827. #endif
  828.           case 'N':                      /* The continuous update animation. */
  829.             xnow = xnow ? 0 : -10;
  830.             break;
  831.           case '!': xnow = -1; break;    /* These are the nine different     */
  832.           case '@': xnow = -2; break;    /* "add time to chart" animations.  */
  833.           case '#': xnow = -3; break;
  834.           case '$': xnow = -4; break;
  835.           case '%': xnow = -5; break;
  836.           case '^': xnow = -6; break;
  837.           case '&': xnow = -7; break;
  838.           case '*': xnow = -8; break;
  839.           case '(': xnow = -9; break;
  840.           case 'V': modex = MODEv; xredraw = TRUE; break; /* Should we go    */
  841.           case 'L': modex = MODEL; xredraw = TRUE; break; /* switch to a     */
  842.           case 'A': modex = MODEg; xredraw = TRUE; break; /* new chart type? */
  843.           case 'Z': modex = MODEZ; xredraw = TRUE; break;
  844.           case 'S': modex = MODES; xredraw = TRUE; break;
  845.           case 'E': modex = MODEE; xredraw = TRUE; break;
  846.           case 'W': modex = MODEW; xredraw = TRUE; break;
  847.           case 'G': modex = MODEG; xredraw = TRUE; break;
  848.           case 'P': modex = MODEP; xredraw = TRUE; break;
  849. #ifdef BIORHYTHM
  850.           case 'Y':               /* Should we switch to biorhythm chart? */
  851.             if (!relation) {
  852.               SetTwin(Mon, Day, Yea, Tim, Zon, Lon, Lat);
  853.             }
  854.             relation = DASHrb;
  855.             modex = MODEb;
  856.             xcast = TRUE;
  857.             break;
  858. #endif
  859.           case '0':
  860.             exdisplay ^= DASHZ0 | DASHEy | DASHXW0;
  861.             modex = (modex == MODEv ? MODEw : (modex == MODEw ? MODEv :
  862.               modex));
  863.             xredraw = TRUE;
  864.             break;
  865.           case 'v': case 'H': case '?':
  866. #ifdef MSG
  867.             _setvideomode(_DEFAULTMODE);
  868.             if (i != 'v')
  869.               _settextrows(43);
  870. #endif
  871.             if (i == 'v')
  872.               ChartLocation();
  873.             else
  874.               XDisplayKeys();
  875. #ifdef MSG
  876.             while (!kbhit())
  877.               ;
  878.             i = getch();
  879.             if (i == 'q' || i == ESCAPE || i == '\3') {
  880.               xbreak = TRUE;
  881.               break;
  882.             }
  883.             XBegin();
  884.             xresize = TRUE;
  885. #endif
  886.             break;
  887. #ifdef MSG
  888.           case '\t':
  889.             if (xscreen == hiresmode)
  890.               xscreen = loresmode;
  891.             else
  892.               xscreen = hiresmode;
  893.             XBegin();
  894.             chartx = config.numxpixels;
  895.             charty = config.numypixels;
  896.             XSquare(&chartx, &charty, FALSE);
  897.             xresize = TRUE;
  898.             break;
  899. #endif
  900.           case '\b':
  901. #ifdef MSG
  902. #ifdef MOUSE
  903.             SetPtrVis(HIDE);
  904. #endif
  905. #endif /* MSG */
  906.             DrawClearScreen();
  907.             break;
  908. #ifdef MOUSE
  909.           case 'z'-'`': coldrw = BLACK;   break;
  910.           case 'e'-'`': coldrw = MAROON;  break;
  911.           case 'f'-'`': coldrw = DKGREEN; break;
  912.           case 'o'-'`': coldrw = ORANGE;  break;
  913.           case 'n'-'`': coldrw = DKBLUE;  break;
  914.           case 'u'-'`': coldrw = PURPLE;  break;
  915.           case 'k'-'`': coldrw = DKCYAN;  break;
  916.           case 'l'-'`': coldrw = LTGRAY;  break;
  917.           case 'd'-'`': coldrw = DKGRAY;  break;
  918.           case 'r'-'`': coldrw = RED;     break;
  919.           case 'g'-'`': coldrw = GREEN;   break;
  920.           case 'y'-'`': coldrw = YELLOW;  break;
  921.           case 'b'-'`': coldrw = BLUE;    break;
  922.           case 'v'-'`': coldrw = MAGENTA; break;
  923.           case 'j'-'`': coldrw = CYAN;    break;
  924.           case 'a'-'`': coldrw = WHITE;   break;
  925. #ifdef MSG
  926.           case 't'-'`':
  927.             SetPtrVis(HIDE);
  928.             if (buttonx >= 0)
  929.               _rectangle(_GBORDER, buttonx, buttony, mousex, mousey);
  930.             SetPtrVis(SHOW);
  931.             break;
  932.           case 'x'-'`':
  933.             SetPtrVis(HIDE);
  934.             if (buttonx >= 0)
  935.               _ellipse(_GBORDER, buttonx, buttony, mousex, mousey);
  936.             SetPtrVis(SHOW);
  937.             break;
  938. #endif
  939. #endif /* MOUSE */
  940.           case 'q': case ESCAPE: case '\3':
  941.             xbreak = TRUE;
  942.             break;
  943.           default:
  944.             if (i > '0' && i <= '9') {
  945. #ifdef MSG
  946.               if (xnow)
  947. #endif
  948.                 /* Process numbers 1..9 signifying animation rate. */
  949.                 dir = (dir > 0 ? 1 : -1)*(i-'0');
  950. #ifdef MSG
  951.               else {
  952.                 /* If we aren't in animation mode, then 1..9 refers to the */
  953.                 /* clipping "quadrant" to use if chart size > screen size. */
  954.                 xcorner = i-'0';
  955.                 xresize = TRUE;
  956.               }
  957. #endif
  958.             break;
  959.             }
  960.             printc(BELL);    /* Any key not bound will sound a beep. */
  961.           }  /* switch */
  962.         }  /* if */
  963. #ifdef X11
  964.       default:
  965.         ;
  966.       }  /* switch */
  967.     }  /* if */
  968. #endif
  969.   }  /* while */
  970. }
  971.  
  972.  
  973. /* This is called right before program termination to get rid of the window. */
  974.  
  975. void XEnd()
  976. {
  977. #ifdef X11
  978.   XFreeGC(disp, gc);
  979.   XFreeGC(disp, pmgc);
  980.   XFreePixmap(disp, pixmap);
  981.   XDestroyWindow(disp, window);
  982.   XCloseDisplay(disp);
  983. #else
  984.   _setvideomode(_DEFAULTMODE);
  985. #endif
  986. }
  987. #endif /* ISG */
  988.  
  989.  
  990. /*
  991. ******************************************************************************
  992. ** Main graphics processing
  993. ******************************************************************************
  994. */
  995.  
  996. /* Print a list of every command switch dealing with the graphics features  */
  997. /* that can be passed to the program, and a description of what it does.    */
  998. /* This is part of what the -H switch prints, if graphics were compiled in. */
  999.  
  1000. void XDisplaySwitches()
  1001. {
  1002.   Prints(" _X: Create a graphics chart instead of displaying it as text.");
  1003. #ifdef ISG
  1004.   Prints(" _Xb: Create bitmap file instead of putting graphics on screen.");
  1005. #endif
  1006.   Prints(" _Xb[n,c,v,a,b]: Set bitmap file output mode to X11 normal,");
  1007.   Prints("     compacted, very compact, Ascii (bmtoa), or Windows bmp.");
  1008. #ifdef PS
  1009.   Prints(" _Xp: Create PostScript stroke graphic instead of bitmap file.");
  1010.   Prints(" _Xp0: Like _Xp but create complete instead of encapsulated file.");
  1011. #endif
  1012. #ifdef META
  1013.   Prints(" _XM[0]: Create Windows metafile stroke graphic instead of bitmap.");
  1014. #endif
  1015.   Prints(" _Xo <file>: Write output bitmap or graphic to specified file.");
  1016. #ifdef X11
  1017.   Prints(" _XB: Display X chart on root instead of in a separate window.");
  1018. #endif
  1019.   Prints(" _Xm: Create monochrome graphic instead of one in color.");
  1020.   Prints(" _Xr: Create chart graphic in reversed colors (white background).");
  1021. #ifdef X11
  1022.   Prints(" _Xw <hor> [<ver>], _ge[..]: Change the size of chart graphic.");
  1023. #else
  1024.   Prints(" _Xw <hor> [<ver>]: Change the size of chart graphic.");
  1025. #endif
  1026.   Prints(" _Xs <100,200,300,400>: Change the size of map or characters by %.");
  1027.   Prints(" _Xi: Create chart graphic in slightly modified form.");
  1028.   Prints(" _XT: Inhibit display of chart info at bottom of graphic.");
  1029.   Prints(" _Xl: Inhibit labeling of object points in chart graphic.");
  1030.   Prints(" _X1 <object>: Rotate wheel charts so object is at left edge.");
  1031.   Prints(" _X2 <object>: Rotate wheel charts so object is at top edge.");
  1032. #ifdef X11
  1033.   Prints(" _Xd <name>, _di[..] <name>: Open X window on specified display.");
  1034. #endif
  1035.   Prints(" _XW: Simply create an image of the world map.");
  1036.   Prints(" _XW0: Like _XW but do a non-rectangular Mollewide projection.");
  1037.   Prints(" _XP: Create just the world map, but from a polar projection.");
  1038.   Prints(" _XG [<degrees>]: Display the image of the world as a globe.");
  1039. #ifdef ISG
  1040.   Prints(" _Xn [<mode>]: Start up chart or globe display in animation mode.");
  1041.   Prints("Also, press 'H' while running for list of key press options.");
  1042. #endif
  1043. }
  1044.  
  1045.  
  1046. /* Process a command line switch passed to the program dealing with the      */
  1047. /* graphics features. This is just like the processing of each switch in the */
  1048. /* main program; however, here each switch has been prefixed with an 'X'.    */
  1049.  
  1050. int XProcessSwitches(argc, argv, pos)
  1051. int argc, pos;
  1052. char **argv;
  1053. {
  1054.   int i = 0;
  1055.   char string[STRING], c;
  1056.  
  1057.   switch (argv[0][pos]) {
  1058.   case '\0':
  1059.     break;
  1060.  
  1061.   case 'b':
  1062.     c = CAP(argv[0][pos+1]);
  1063.     if (IsValidBmpmode(c))
  1064.       bitmapmode = c;
  1065.     xbitmap = TRUE;
  1066.     psfile = metafile = FALSE;
  1067.     break;
  1068.  
  1069. #ifdef PS
  1070.   case 'p':
  1071.     psfile = TRUE + (argv[0][pos+1] != '0');
  1072.     xbitmap = metafile = FALSE;
  1073.     break;
  1074. #endif
  1075.  
  1076. #ifdef META
  1077.   case 'M':
  1078.     if (argv[0][pos+1] == '0')
  1079.       xfont = !xfont;
  1080.     metafile = TRUE;
  1081.     xbitmap = psfile = FALSE;
  1082.     break;
  1083. #endif
  1084.  
  1085.   case 'o':
  1086.     if (argc <= 1) {
  1087.       TooFew("Xo");
  1088.       return -1;
  1089.     }
  1090.     if (!xbitmap && !psfile && !metafile)
  1091.       xbitmap = TRUE;
  1092.     outputfile = argv[1];
  1093.     i++;
  1094.     break;
  1095.  
  1096. #ifdef X11
  1097.   case 'B':
  1098.     xroot = !xroot;
  1099.     break;
  1100. #endif
  1101.  
  1102.   case 'm':
  1103.     xcolor = !xcolor;
  1104.     break;
  1105.  
  1106.   case 'r':
  1107.     xreverse = !xreverse;
  1108.     break;
  1109.  
  1110.   case 'w':
  1111.     if (argc <= 1) {
  1112.       TooFew("Xw");
  1113.       return -1;
  1114.     }
  1115.     chartx = atoi(argv[1]);
  1116.     if (argc > 2 && (charty = atoi(argv[2]))) {
  1117.       argc--; argv++;
  1118.       i++;
  1119.     } else
  1120.       charty = chartx;
  1121.     if (!IsValidGraphx(chartx)) {
  1122.       BadVal("Xw", chartx);
  1123.       return -1;
  1124.     }
  1125.     if (!IsValidGraphy(charty)) {
  1126.       BadVal("Xw", charty);
  1127.       return -1;
  1128.     }
  1129.     i++;
  1130.     break;
  1131.  
  1132.   case 's':
  1133.     if (argc <= 1) {
  1134.       TooFew("Xs");
  1135.       return -1;
  1136.     }
  1137.     scale = atoi(argv[1]);
  1138.     if (scale < 100)
  1139.       scale *= 100;
  1140.     if (!IsValidScale(scale)) {
  1141.       BadVal("Xs", scale);
  1142.       return -1;
  1143.     }
  1144.     i++;
  1145.     break;
  1146.  
  1147.   case 'i':
  1148.     xbonus = !xbonus;
  1149.     break;
  1150.  
  1151.   case 'T':
  1152.     xtext = !xtext;
  1153.     break;
  1154.  
  1155.   case 'l':
  1156.     xlabel = !xlabel;
  1157.     break;
  1158.  
  1159.   case '1':
  1160.     if (argc <= 1) {
  1161.       TooFew("X1");
  1162.       return -1;
  1163.     }
  1164.     xeast = atoi(argv[1]);
  1165.     if (!IsItem(xeast)) {
  1166.       BadVal("X1", xeast);
  1167.       return -1;
  1168.     }
  1169.     i++;
  1170.     break;
  1171.  
  1172.   case '2':
  1173.     if (argc <= 1) {
  1174.       TooFew("X2");
  1175.       return -1;
  1176.     }
  1177.     xeast = atoi(argv[1]);
  1178.     if (!IsItem(xeast)) {
  1179.       BadVal("X2", xeast);
  1180.       return -1;
  1181.     }
  1182.     xeast = -xeast;
  1183.     i++;
  1184.     break;
  1185.  
  1186.   case 'd':
  1187.     if (argc <= 1) {
  1188.       TooFew("Xd");
  1189.       return -1;
  1190.     }
  1191.     dispname = argv[1];
  1192.     i++;
  1193.     break;
  1194.  
  1195.   case 'W':
  1196.     if (argc > 1 && ((degree = atoi(argv[1])) || argv[1][0] == '0')) {
  1197.       i++;
  1198.       if (degree < 0 || degree >= DEGD) {
  1199.         BadVal("XW", degree);
  1200.         return -1;
  1201.       }
  1202.     } else
  1203.       degree = 0;
  1204.     modex = MODEW;
  1205.     if (argv[0][pos+1] == '0')
  1206.       exdisplay |= DASHXW0;
  1207.     autom = TRUE;
  1208.     break;
  1209.  
  1210.   case 'P':
  1211.     if (argc > 1 && ((degree = atoi(argv[1])) || argv[1][0] == '0')) {
  1212.       i++;
  1213.       if (degree < 0 || degree >= DEGD) {
  1214.         BadVal("XP", degree);
  1215.         return -1;
  1216.       }
  1217.     } else
  1218.       degree = 0;
  1219.     modex = MODEP;
  1220.     if (argv[0][pos+1] == '0')
  1221.       exdisplay |= DASHXP0;
  1222.     autom = TRUE;
  1223.     break;
  1224.  
  1225.   case 'G':
  1226.     if (argc > 1 && ((degree = atoi(argv[1])) || argv[1][0] == '0')) {
  1227.       i++;
  1228.       if (degree < 0 || degree >= DEGD) {
  1229.         BadVal("XG", degree);
  1230.         return -1;
  1231.       }
  1232.       if (argc > 2 && ((tilt = atof(argv[2])) || argv[2][0] == '0')) {
  1233.         i++;
  1234.         if (tilt < -DEGQUAD || tilt > DEGQUAD) {
  1235.           BadVal2("XG", tilt);
  1236.           return -1;
  1237.         }
  1238.       }
  1239.     }
  1240.     modex = MODEG;
  1241.     autom = TRUE;
  1242.     break;
  1243.  
  1244. #ifdef ISG
  1245.   case 'n':
  1246.     if (argc > 1 && (xnow = atoi(argv[1])))
  1247.       i++;
  1248.     else
  1249.       xnow = 10;
  1250.     if (xnow < 1 || xnow > 10) {
  1251.       BadVal("Xn", xnow);
  1252.       return -1;
  1253.     }
  1254.     break;
  1255. #endif
  1256.  
  1257.   default:
  1258.     sprintf(string, "Unknown switch '%s'", argv[0]);
  1259.     PrintError(string);
  1260.     return -1;
  1261.   }
  1262.   return i;    /* 'i' contains the value to be added to argc when we return. */
  1263. }
  1264.  
  1265.  
  1266. /* This is the main interface to all the graphics features. This routine     */
  1267. /* is called from the main program if any of the -X switches were specified, */
  1268. /* and it sets up for and goes and generates the appropriate graphics chart. */
  1269. /* We return TRUE if successfull, FALSE if some non-fatal error occurred.    */
  1270.  
  1271. bool XAction()
  1272. {
  1273.   char string[STRING];
  1274.  
  1275.   xfile = (xbitmap || psfile || metafile);
  1276.  
  1277.   /* First figure out what graphic mode to generate the chart in, based on */
  1278.   /* various non-X command switches, e.g. -L combined with -X, -g combined */
  1279.   /* with -X, and so on, and determine the size the window is to be, too.  */
  1280.  
  1281.   if (modex == MODEv) {
  1282.     if (todisplay & DASHw)
  1283.       modex = MODEw;
  1284.     else if (todisplay & DASHL)
  1285.       modex = MODEL;
  1286.     else if ((todisplay & DASHg) | (todisplay & DASHm)) {
  1287.       modex = MODEg;
  1288.       if (relation <= DASHr0 &&
  1289.         (todisplay & DASHm) > 0 && (exdisplay & DASHm0) == 0)
  1290.         exdisplay |= DASHg0;
  1291.       chartx = charty =
  1292.                 (gridobjects + (relation <= DASHr0))*CELLSIZE*SCALE + 1;
  1293.     } else if (todisplay & DASHZ)
  1294.       modex = MODEZ;
  1295.     else if (todisplay & DASHS)
  1296.       modex = MODES;
  1297.     else if (todisplay & DASHE)
  1298.       modex = MODEE;
  1299.     else if (relation == DASHrb)
  1300.       modex = MODEb;
  1301.   }
  1302.   if (ISSIDEBAR)
  1303.     chartx += SIDESIZE;
  1304.   if (modex == MODEL || modex == MODEW) {
  1305.     chartx = DEGD*SCALE+2;
  1306.     charty = (90*2+1)*SCALE+2;
  1307.   }
  1308.   scalet = psfile ? PSMUL : (metafile ? METAMUL : 1);
  1309.   if (xfile) {
  1310.     if (chartx > BITMAPX)
  1311.       chartx = BITMAPX;
  1312.     if (charty > BITMAPY)
  1313.       charty = BITMAPY;
  1314.     if (xbitmap) {
  1315.       bitmaprow = (chartx + 1) >> 1;
  1316.       Allocate(bm, (long)bitmaprow * charty, bitmap);
  1317.       if (bm == NULL) {
  1318.         sprintf(string,
  1319.           "Not enough memory for %d by %d bitmap (%ld bytes).",
  1320.           chartx, charty, (long)bitmaprow * charty);
  1321.         PrintError(string);
  1322.         return FALSE;
  1323.       }
  1324.     }
  1325. #ifdef PS
  1326.     else if (psfile)
  1327.         PSbegin();
  1328. #endif
  1329.     else {
  1330.       Allocate(bm, MAXMETA, bitmap);
  1331.       if (bm == NULL) {
  1332.         sprintf(string,
  1333.           "Not enough memory for metafile. (%ld bytes.)", MAXMETA);
  1334.         PrintError(string);
  1335.         return FALSE;
  1336.       }
  1337.       chartx *= METAMUL;    /* Increase chart sizes and scales behind the */
  1338.       charty *= METAMUL;    /* scenes to make graphics look smoother.     */
  1339.       scale  *= METAMUL;
  1340.     }
  1341.     XColorInit();
  1342.   }
  1343. #ifdef ISG
  1344.   else
  1345.     XBegin();
  1346. #endif
  1347.   if (xroot || xfile)    /* Go draw the graphic chart. */
  1348.     XChart();
  1349.   if (xfile) {    /* Write bitmap to file if in that mode. */
  1350.     WriteFile();
  1351.     if (!psfile)
  1352.       Deallocate(bm);
  1353.   }
  1354. #ifdef ISG
  1355.   else {
  1356. #ifdef X11
  1357.     if (xroot) {
  1358.       XSetWindowBackgroundPixmap(disp, root, pixmap);    /* Process -XB. */
  1359.       XClearWindow(disp, root);
  1360.  
  1361.       /* If -Xn in effect with -XB, then enter infinite loop where we */
  1362.       /* calculate and animate chart, displaying on the root window.  */
  1363.       if (xnow)
  1364.         loop {
  1365.           Animate(xnow, 1);
  1366.           if (relation > DASHr0 || (modex != MODEZ && modex != MODES))
  1367.             XFillRectangle(disp, pixmap, pmgc, 0, 0, chartx, charty);
  1368.           XChart();
  1369.           XSetWindowBackgroundPixmap(disp, root, pixmap);
  1370.           XClearWindow(disp, root);
  1371.         }
  1372.     } else
  1373. #endif
  1374.       XSpin();    /* Window's up; process commands given to window now. */
  1375.     XEnd();
  1376.   }
  1377. #endif /* ISG */
  1378.   return TRUE;
  1379. }
  1380. #endif /* GRAPH */
  1381.  
  1382. /* xdriver.c */
  1383.